package com.k8.rpc.url;


import com.k8.common.factroy.loader.ExtensionAccessor;
import com.k8.common.util.StrUtil;
import com.k8.rpc.util.URLUtils;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.*;

import static com.k8.common.constants.CommonKeyConstants.*;
import static com.k8.common.constants.CommonKeyConstants.RegistryKeyConstant.REGISTRY_KEY;


public class URL {
    private boolean system_first = true;

    public URL() {
    }

    public URL(URL systemConfigUrl) {
        this.systemConfigUrl = systemConfigUrl;
    }

    private ExtensionAccessor extensionAccessor;
    private URL systemConfigUrl;

    private final URLAddress address = new URLAddress();


    public URLAddress getAddress() {
        return address;
    }

    private final Map<String, String> urlParams = new HashMap<>();


    private Map<String, Object> attributes;//附加物

    private volatile String cacheURLKey;

    public String getCacheURLKey() {
        return cacheURLKey;
    }

    public void setCacheURLKey(String cacheURLKey) {
        this.cacheURLKey = cacheURLKey;
    }

    public String getSimpleString() {
        StringBuilder stringBuilder = new StringBuilder();
        StringBuilder builder = stringBuilder.append(getProtocol())
                .append("://")
                .append(address);
        return builder.toString();
    }

    @Override
    public String toString() {
        StringBuilder stringBuilder = new StringBuilder();
        StringBuilder builder = stringBuilder.append(getProtocol())
                .append("://")
                .append(address)
                .append("?");
        Set<String> paraKeys = urlParams.keySet();
        for (String paraName : paraKeys) {
            String paraValue = urlParams.get(paraName);
            builder.append(paraName).append("=").append(paraValue).append("&");
        }
        if (paraKeys.size() > 0) {
            builder.deleteCharAt(stringBuilder.length() - 1);
        }
        return builder.toString();
    }

    public URL removeAttribute(String key) {
        urlParams.remove(key);
        return this;
    }

    public Map<String, String> getUrlParams() {
        //todo 需要优化
        return Collections.unmodifiableMap(this.urlParams);
    }

    public String getPath() {
        return this.address.getPath();
    }

    public int getPort() {
        return this.address.getPort();
    }

    public int getPort(int defaultPort) {
        int port = this.address.getPort();
        if (port > 0) return port;
        return defaultPort;
    }

    public String getHost() {
        return this.address.getHost();
    }

    public URL setPath(String path) {
        this.address.setPath(path);
        return this;
    }

    public URL setPort(int port) {
        this.address.setPort(port);
        return this;
    }

    public URL setHost(String host) {
        this.address.setHost(host);
        return this;
    }

    public static String encode(String value) {
        if (StrUtil.isEmpty(value)) {
            return "";
        }
        try {
            return URLEncoder.encode(value, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    /**
     * 优先以系统参数作为值返回，而不是通过配置文件所生成的
     * {@link URLUtils#buildSystemURL()}
     * 中将对应的系统参数添加进systemUrl
     *
     * @param key
     * @return
     */
    public String getParameter(String key) {
        if (system_first && systemConfigUrl != null) {
            String value = systemConfigUrl.getParameter(key);
            if (value == null) {
                return this.urlParams.get(key);
            }
            return value;
        } else {
            String value = this.urlParams.get(key);
            if (value == null && systemConfigUrl != null) {
                return systemConfigUrl.getParameter(key);
            }
            return value;
        }
    }

    public String getParameter(String key, String defaultValue) {
        String value = getParameter(key);
        return StrUtil.isEmpty(value) ? defaultValue : defaultValue.trim();
    }

    public int getParameter(String key, int defaultValue) {
        String value = getParameter(key);
        return StrUtil.isEmpty(value) ? defaultValue : Integer.parseInt(value);
    }

    public long getParameter(String key, long defaultValue) {
        String value = getParameter(key);
        return StrUtil.isEmpty(value) ? defaultValue : Integer.parseInt(value);
    }

    public boolean getParameter(String key, boolean defaultValue) {
        String value = getParameter(key);
        return StrUtil.isEmpty(value) ? defaultValue : Boolean.parseBoolean(value);
    }

    public URL removeParameter(String key) {
        urlParams.remove(key);
        return this;
    }


    public void setParameter(String key, String value) {
        this.urlParams.put(key, value);
    }

    public URL setMethods(List<Method> methods) {
        URLUtils.setMethods(this, methods);
        return this;
    }

    public String getMethodString() {
        return getParameter(METHODS_KEY);
    }

    public URL setProtocol(String protocol) {
        setParameter(PROTOCOL_KEY, protocol);
        return this;
    }

    public String getProtocol() {
        return getParameter(PROTOCOL_KEY);
    }

    public void setExtensionAccessor(ExtensionAccessor extensionAccessor) {
        this.extensionAccessor = extensionAccessor;
    }

    public ExtensionAccessor getExtensionAccessor() {
        if (this.extensionAccessor != null) return this.extensionAccessor;
        return systemConfigUrl.getExtensionAccessor();
    }

    public URL setVersion(String version) {
        setParameter(VERSION_KEY, version);
        return this;
    }

    public String getVersion() {
        return getParameter(VERSION_KEY, "");
    }

    public URL setInterface(String ref) {
        setParameter(INTERFACE_KEY, ref);
        return this;
    }

    //服务夫接口
    public String getInterface() {
        return getParameter(INTERFACE_KEY, "");
    }

    public URL setSerialize(String serialize) {
        setParameter(SERIALIZE_KEY, serialize);
        return this;
    }

    public String getSerialize() {
        return getParameter(SERIALIZE_KEY);
    }

    public URL setInstance(String instance) {
        setParameter(INSTANCE_KEY, instance);
        return this;
    }

    public String getInstance() {
        return getParameter(INSTANCE_KEY);
    }

    public URL setRegistryName(String registry) {
        setParameter(REGISTRY_KEY, registry);
        return this;
    }

    public String getRegistryName() {
        return getParameter(REGISTRY_KEY);
    }

    public URL setProxy(String proxy) {
        setParameter(PROXY_KEY, proxy);
        return this;
    }

    public String getProxy() {
        return getParameter(PROXY_KEY);
    }

    public URL setAppName(String appName) {
        setParameter(APP_KEY, appName);
        return this;
    }

    public String getAppName() {
        return getParameter(APP_KEY);
    }

    public void putAttribute(String key, Object value) {
        if (this.attributes == null) this.attributes = new HashMap<>();
        this.attributes.put(key, value);
    }

    public Object getAttribute(String key) {
        if (this.attributes == null) return null;
        return this.attributes.get(key);
    }


    public String getSide() {
        String side = getParameter(SIDE_KEY);
        if (side == null) return PROVIDER;
        return side;
    }

    public void setSide(String side) {
        setParameter(SIDE_KEY, side);
    }

    public String getSide(String defaultSide) {
        String side = getParameter(SIDE_KEY);
        if (StrUtil.isEmpty(side)) return defaultSide;
        return side;
    }

    public String getIp() {
        return this.address.getIp();
    }

    public String getExchange() {
        return this.getParameter(EXCHANGE_KEY, "defaultExchange");
    }

    public String getUserName() {
        return getParameter(USER_NAME);
    }

    public String getUserName(String defaultValue) {
        return getParameter(USER_NAME, defaultValue);
    }

    public URL setUserName(String userName) {
        setParameter(USER_NAME, userName);
        return this;
    }

    public String getPassWord() {
        return getParameter(PASSWORD);
    }

    public URL setPassWord(String passWord) {
        setParameter(PASSWORD, passWord);
        return this;
    }

    public String getPassWord(String defaultValue) {
        return getParameter(PASSWORD, defaultValue);
    }


    public String getGroup() {
        return getParameter(GROUP_KEY, "");
    }


    public Map<String, Object> getAttributes() {
        if (this.attributes == null) return null;
        return Collections.unmodifiableMap(this.attributes);
    }

    public void setSystemConfigUrl(URL url) {
        this.systemConfigUrl = url;
    }

    public URL getSystemConfigUrl() {
        return systemConfigUrl;
    }

    public boolean isSystem_first() {
        return system_first;
    }

    public void setSystem_first(boolean system_first) {
        this.system_first = system_first;
    }
}
